package com.zs.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by youx on 2017-06-05.
 */
public class TCPServerManager {
    private static TCPServerManager mInstance;
    private Selector mSelector;
    private ServerSocketChannel mChannel;
    private ExecutorService mSendPool;
    private ReceiveThread mReceiveThread;


    private TCPServerManager(){
        try {
            mSendPool= Executors.newSingleThreadExecutor();
            connect();
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    private void connect() throws IOException {
        mSelector=Selector.open();
        mChannel= ServerSocketChannel.open();
        mChannel.socket().bind(new InetSocketAddress(8080));
        mChannel.configureBlocking(false);
        mChannel.register(mSelector, SelectionKey.OP_ACCEPT);

        if(mReceiveThread==null){
            mReceiveThread=new ReceiveThread();
        }
        //接收发送过来的数据
        mReceiveThread.start();
    }

    public static TCPServerManager getTnstance(){
        if(mInstance==null){
            synchronized (TCPServerManager.class){
                if(mInstance==null){
                    mInstance=new TCPServerManager();
                }
            }
        }
        return mInstance;
    }



    public void sendMsg(String msg,SocketChannel mChannel){
        mSendPool.execute(new SendWorker(msg,mChannel));
    }

    /**
     * 接收数据
     */
    class ReceiveThread extends Thread{

        @Override
        public void run(){
           while (true){
               try {
                   if(mSelector.select()==0){
                       continue;
                   }
                   Iterator<SelectionKey> itor=mSelector.selectedKeys().iterator();
                   while (itor.hasNext()){
                       SelectionKey key=itor.next();

                       if(key.isAcceptable()){
                           ServerSocketChannel ch= (ServerSocketChannel) key.channel();
                           SocketChannel sc=ch.accept();//创建于客户端的正式连接
                           if(sc!=null){
                               sc.configureBlocking(false);
                               sc.register(mSelector,SelectionKey.OP_READ);
                           }
                       }else if(key.isReadable()){
                           key.interestOps(SelectionKey.OP_WRITE);
                           SocketChannel clientChannel = (SocketChannel) key.channel();
                           InetSocketAddress address=(InetSocketAddress) clientChannel.getRemoteAddress();
                           int port=address.getPort();
                           String host=address.getHostString();
                           ByteBuffer buffer=ByteBuffer.allocate(1024);
                           if(clientChannel.read(buffer)!=-1){
                               buffer.flip();
                               byte[] b=buffer.array();
                               System.out.println("[HOST:"+host+",PORT:"+port+"]"+new String(b,0,b.length));
                           }
                           key.interestOps(SelectionKey.OP_WRITE);


                       }else if(key.isWritable()){
                           SocketChannel ch= (SocketChannel) key.channel();
                           String ip = ch.socket().getInetAddress().getHostAddress();
                           int port = ch.socket().getLocalPort();

                           String msg=ip+":"+port+"你的消息收到";
                           sendMsg(msg,ch);
                       }
                   }
               }catch (Exception e){
                   e.printStackTrace();
               }

           }
        }
    }

    /**
     * 响应数据
     */
    class SendWorker extends Thread{
        private String msg;
        private SocketChannel sendChannel;
        SendWorker(String msg,SocketChannel sendChannel){
            this.msg=msg;
            this.sendChannel=sendChannel;
        }

        @Override
        public void run() {
            byte[] byte_msg=msg.getBytes();
            int bodyLen=byte_msg.length;
            int packLen=bodyLen+4;
            ByteBuffer byteBuffer=ByteBuffer.allocate(packLen);
            byteBuffer.putInt(packLen);
            byteBuffer.put(byte_msg);
            byteBuffer.flip();
            try {
                if(sendChannel.isConnected() && sendChannel!=null){
                    String ip=sendChannel.socket().getInetAddress().getHostAddress();
                    int sendLen=sendChannel.write(byteBuffer);
                    System.out.println("发送给客户端["+ip+"]-->数据长度:"+sendLen);
                }else{
                    System.out.println("与客户端断开连接");
                }
            }catch (Exception e){
                e.printStackTrace();
            }


        }
    }

    public static void main(String[] args) {
        TCPServerManager.getTnstance();
    }


}
